package hotel.controller.room;

import javafx.fxml.FXML;

import javafx.scene.control.Button;

import javafx.scene.control.TextField;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Iterator;
import java.util.List;

import hotel.common.Comm;
import hotel.common.MsgBox;
import hotel.dao.HotelDao;
import hotel.modal.Customer;
import hotel.modal.CustomerType;
import hotel.modal.Room;
import hotel.modal.RoomRent;
import hotel.modal.RoomType;
import hotel.modal.User;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;

import javafx.scene.control.TitledPane;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.ComboBox;

import javafx.scene.control.Spinner;
import javafx.scene.control.ChoiceBox;

public class RoomRentController {
	@FXML
	private TitledPane titledPane;
	@FXML
	private TextField nameField;
	@FXML
	private ChoiceBox<String> genderCh;
	@FXML
	private TextField phoneField;
	@FXML
	private ComboBox<CustomerType> typeCb;
	@FXML
	private Label discountLbl;
	@FXML
	private Label creditLbl;
	@FXML
	private TextField certIdField;
	@FXML
	private Button btnQuery;
	@FXML
	private Spinner<Integer> daySpinner;
	@FXML
	private ComboBox<RoomType> roomTypeCb;
	@FXML
	private ComboBox<Room> roomCb;
	@FXML
	private TextField depositField;
	@FXML
	private Button btnCancel;
	@FXML
	private Button btnOk;
	@FXML
	private TextField commentField;
	
	private RoomRent roomRent;
	private Room room;
	private Customer customer;
	private boolean customerAdd = true;
	private User user = null;


	@FXML
	public void initialize() {
		initComponent();
		initData();
	}
	
	public Room getRoom() {
		return room;
	}

	public void setRoom(Room room) {
		this.room = room;
		if(this.room == null) return ;
		roomTypeCb.getSelectionModel().select(findRoomTypeCbIndex(this.room));
		roomCb.getSelectionModel().select(findRoomCbIndex(this.room));
	}
	
	private void initData() {
		List<RoomType> list = HotelDao.getAllRoomType();
		ObservableList<RoomType> roomTypeItems = roomTypeCb.getItems();
		roomTypeItems.addAll(list);
		if(list.size() > 0) roomTypeCb.getSelectionModel().select(0);
		
		ObservableList<CustomerType> items = typeCb.getItems();
		List<CustomerType> customerType = HotelDao.getAllCustomerType();
		items.addAll(customerType);
		if(items.size() > 0) typeCb.getSelectionModel().select(0);
		
		titledPane.setText("客户资料（新增）");
	}
	
	private void initComponent() {
		roomTypeCb.setCellFactory(new Callback<ListView<RoomType>, ListCell<RoomType>>() { // 下拉列表显示
			@Override
			public ListCell<RoomType> call(ListView<RoomType> p) {
				ListCell<RoomType> cell = new ListCell<RoomType>() {
					@Override
					protected void updateItem(RoomType item, boolean empty) {
						super.updateItem(item, empty);
						if (empty) {
							setText("");
						} else {
							if (item.isHourRoom())
								setText(item.getTypeName() + "(钟点房)");
							else
								setText(item.getTypeName());
						}
					}
				};
				return cell;
			}
		});
		
		roomTypeCb.setButtonCell(new ListCell<RoomType>() {
			@Override
			protected void updateItem(RoomType item, boolean empty) {
				super.updateItem(item, empty);
				if (empty) {
					setText("");
				} else {
					if(item.isHourRoom()) setText(item.getTypeName() + "(钟点房)");
					else setText(item.getTypeName());
				}
			}
		});
	
		roomTypeCb.valueProperty().addListener(new ChangeListener<RoomType>() { // 房间类型ComBobox监听
			@Override
			public void changed(ObservableValue<? extends RoomType> observable, RoomType oldValue, RoomType newValue) {
				if(newValue == null) return;
				List<Room> rList = runRoomCbFilter(HotelDao.getRoomList(newValue)); // 从数据库拉取房间信息
				ObservableList<Room> obList = FXCollections.observableArrayList(rList);
				roomCb.setItems(obList);
				if(obList.size() > 0) {
					roomCb.getSelectionModel().select(0);
					depositField.setText(String.format("%.2f", newValue.getDeposit()));
				}
			}
	    });
		
		roomCb.setCellFactory(new Callback<ListView<Room>, ListCell<Room>>() { // 下拉列表显示
			@Override
			public ListCell<Room> call(ListView<Room> p) {
				ListCell<Room> cell = new ListCell<Room>() {
					@Override
					protected void updateItem(Room item, boolean empty) {
						super.updateItem(item, empty);
						if (empty) {
							setText("");
						} else {
							String str = String.format("  (%.2f元/%s)", item.getPrice(), item.isHourRoom()?"小时":"天");
							setText(item.getRoomNo()+str);
						}
					}
				};
				return cell;
			}
		});
		
		roomCb.setButtonCell(new ListCell<Room>() {
			@Override
			protected void updateItem(Room item, boolean empty) {
				super.updateItem(item, empty);
				if (empty) {
					setText("");
				} else {
					String str = String.format("  (%.2f元/%s)", item.getPrice(), item.isHourRoom()?"小时":"天");
					setText(item.getRoomNo()+str);
				}
			}
		});
		
		roomCb.valueProperty().addListener(new ChangeListener<Room>() {
			@Override
			public void changed(ObservableValue<? extends Room> observable, Room oldValue, Room newValue) {
				if(newValue == null) {
					btnOk.setDisable(true);
				}else {
					if(btnOk.isDisable()) btnOk.setDisable(false);
					room = roomCb.getSelectionModel().getSelectedItem();
					
				}	
			}
		});
		
		typeCb.setCellFactory(new Callback<ListView<CustomerType>, ListCell<CustomerType>>() {
			@Override
			public ListCell<CustomerType> call(ListView<CustomerType> param) {
				ListCell<CustomerType> cell = new ListCell<CustomerType>() {
					@Override
					protected void updateItem(CustomerType item, boolean empty) {
						super.updateItem(item, empty);
						if (empty) {
							setText("");
						} else {
							setText(item.getTypeName());
						}
					}
				};
				return cell;
			}
		});
		
		typeCb.setButtonCell(new ListCell<CustomerType>() {
			@Override
			protected void updateItem(CustomerType item, boolean empty) {
				super.updateItem(item, empty);
				if (empty) {
					setText("");
				} else {
					setText(item.getTypeName());
				}
			}
		});
		
		typeCb.valueProperty().addListener(new ChangeListener<CustomerType>() {
			@Override
			public void changed(ObservableValue<? extends CustomerType> observable, CustomerType oldValue,
					CustomerType newValue) {
				if(newValue != null) {
					discountLbl.setText(String.valueOf(newValue.getDiscountRate()));
				}else {
					discountLbl.setText("1.0");
				}
			}
		});
		
		daySpinner.focusedProperty().addListener((s, ov, nv) -> {
		    if (nv) return;
		    Comm.commitEditorText(daySpinner); 
		});
		
		daySpinner.valueProperty().addListener(new ChangeListener<Integer>() {
			@Override
			public void changed(ObservableValue<? extends Integer> observable, Integer oldValue, Integer newValue) {
				if(newValue == null) return;
			    RoomType roomType = roomTypeCb.getSelectionModel().getSelectedItem();
			    if(roomType == null) return;
			    depositField.setText(String.format("%.2f", roomType.getDeposit() + (newValue-1)*roomType.getPrice())); // 押金计算
			}
		});
		
		
		depositField.setTextFormatter(Comm.getDecimalFormatter());			// 设置只能输入Number
		phoneField.textProperty().addListener(Comm.getNumberTextFieldListener(phoneField)); // 设置只能输入数字
		
	}
	
	
	private int findRoomTypeCbIndex(RoomType rt) {
		if(rt == null) return 0;
		ObservableList<RoomType> items = roomTypeCb.getItems();
		RoomType t = null;
		for(int i = 0; i < items.size(); i++) {
			t = items.get(i);
			if(t!= null && rt.getTypeId() == t.getTypeId()) return i;
		}
		return 0;
	}
	
	private int findRoomCbIndex(Room r) {
		if(r == null) return 0;
		ObservableList<Room> items = roomCb.getItems();
		Room t = null;
		for(int i = 0; i < items.size(); i++) {
			t = items.get(i);
			if(t!= null && r.getRoomNo().equals(t.getRoomNo())) return i;
		}
		return 0;
	}
	
	private List<Room> runRoomCbFilter(List<Room> list) {
		Iterator<Room> iter = list.iterator();
		Room room = null;
		while(iter.hasNext()) {
			room = iter.next();
			if(room.getStatus() > 2) { // 状态为可供或者预定的房间才可以入住
				iter.remove();			// 将不符合要求的房间移除
			}
		}
		return list;
	}
	
	private int findTypeCbIndex(CustomerType ct) {
		if(ct == null) return 0;
		ObservableList<CustomerType> items = typeCb.getItems();
		CustomerType t = null;
		for(int i = 0; i < items.size(); i++) {
			t = items.get(i);
			if(t!= null && ct.getCustomerTypeId() == t.getCustomerTypeId()) 
				return i;
		}
		return 0;
	}

	// Event Listener on Button[#btnQuery].onAction
	@FXML
	public void onBtnQueryAction(ActionEvent event) {
		queryAndShowCustomer(true);
	}
	
	private void queryAndShowCustomer(boolean clear) { // clear表示查询不到信息时，是否清除旧的内容
		String certId = certIdField.getText().toUpperCase();
		String title = "客户资料";
		if(certId.equals("")) return ; 
		customer = HotelDao.getCustomer(certId); // 根据certId读取数据库客户信息
		if(customer == null) {
			customerAdd = true;
			titledPane.setText(title + "（新增）");
			if(clear) {
				nameField.clear();
				phoneField.clear();
				typeCb.getSelectionModel().select(0);
				creditLbl.setText("0.00");
			}
		}
		else {
			customer.setModified(false);
			titledPane.setText(title + String.format("（客户编号：%d）", customer.getCustomerNo()));
			certIdField.setText(customer.getCertId());
			nameField.setText(customer.getName());
			phoneField.setText(customer.getPhone());
			typeCb.getSelectionModel().select(findTypeCbIndex(customer));
			creditLbl.setText(String.format("%.2f", customer.getCredit()));
			customerAdd = false;
		}
	}
	
	// Event Listener on Button[#btnOk].onAction
	@FXML
	public void onBtnOkAction(ActionEvent event) {
		String name = nameField.getText();
		String phone = phoneField.getText();
		String certId = certIdField.getText();
		String gender = genderCh.getSelectionModel().getSelectedItem();
		int typeId = typeCb.getSelectionModel().getSelectedItem().getCustomerTypeId();
		room = roomCb.getSelectionModel().getSelectedItem();
		
		if(room == null) {
			MsgBox.showWarningDialog("提示", null, "请选择一个房间！");
			return ;
		}
		
		if(certId.equals("")) {
			MsgBox.showWarningDialog("提示", null, "证件号码不允许为空！");
			certIdField.requestFocus();
			return ;
		}
		
		if(name.equals("")) {
			MsgBox.showWarningDialog("提示", null, "名字不允许为空！");
			nameField.requestFocus();
			return ;
		}
		
		
		if(customerAdd) {
			customer = new Customer();
			customer.setModified(true);
			customer.setName(name);
			customer.setCertId(certId);
			customer.setGender(gender);
			customer.setPhone(phone);
			customer.setCustomerTypeId(typeId);
			customer.setCredit(0.0);
			if(HotelDao.add(customer)) {				 // 如果客户信息添加成功
				queryAndShowCustomer(false);
			}
		}else {
			customer.setModified(false); 	// 对比查看客户信息是否需要更新
			if(!customer.getName().equals(name)) { customer.setName(name); customer.setModified(true); }
			if(!customer.getGender().equals(gender)) { customer.setGender(gender); customer.setModified(true); }
			if(!customer.getPhone().equals(phone)) { customer.setPhone(phone); customer.setModified(true); }
			if(customer.getCustomerTypeId() != typeId) { customer.setCustomerTypeId(typeId); customer.setModified(true); }
			
			if(customer.isModified()) { // 如果客户信息更新成功，则改变modified标志为false
				if(HotelDao.update(customer)) customer.setModified(false);
			}
		}
		
		if(customer.isModified()) { 
			MsgBox.showErrorDialog("错误", null, "客户信息未能成功写入数据库!");
			return ;
		}
		
		LocalDateTime now = LocalDateTime.now();
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		String startTime = now.format(formatter);
		
		roomRent = new RoomRent();
		roomRent.setCustomerNo(customer.getCustomerNo());
		roomRent.setRoomNo(room.getRoomNo());
		roomRent.setStartTime(startTime);
		roomRent.setDuration(daySpinner.getValue());
		roomRent.setDeposit(Double.valueOf(depositField.getText()).doubleValue());
		roomRent.setCreateTime(startTime);
		roomRent.setValid(true);
		roomRent.setComment(commentField.getText());
		roomRent.setOperateUser1(user.getUserName());
		room.setStatus(3);
		room.setModified(true);
		
		hideWindow();
		if(HotelDao.update(room) && HotelDao.add(roomRent)) {
			MsgBox.showInformationDialog("提示", null, "入住信息添加成功！");
		}else {
			room.setModified(false);
			MsgBox.showErrorDialog("错误", null, "入住信息写入数据库失败！");
		}
		closeWindow();
	}
	
	// Event Listener on Button[#btnCancel].onAction
	@FXML
	public void onBtnCancelAction(ActionEvent event) {
		closeWindow();
	}
	
	private void hideWindow() {
		Stage stage = (Stage)btnCancel.getScene().getWindow();
		stage.hide();
	}
	
	private void closeWindow() {
		Stage stage = (Stage)btnCancel.getScene().getWindow();
		stage.close();
	}
	
	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}
}
